<?php
/**
 * V4版本
 */
namespace app\admin\service;

use app\index\model\FileOss as FileOssModal;
use OSS\Core\OssException;
use OSS\Credentials\StaticCredentialsProvider;
use OSS\OssClient;
use OSS\Http\RequestCore;
use OSS\Http\ResponseCore;
use think\facade\Log;

class OssService
{
    protected $ossClient;
    private $accessKeyId;
    private $accessKeySecret;
    private $endpoint;
    private $bucket;
    public function __construct(){
        $this->accessKeyId=config('oss.accessKeyId');
        $this->accessKeySecret=config('oss.accessKeySecret');
        $this->endpoint=config('oss.endpoint');
        $this->bucket=config('oss.bucket');

        $provider = new StaticCredentialsProvider(
            $this->accessKeyId,
            $this->accessKeySecret
        );
        $config = array(
            'region' => 'cn-hangzhou',
            'endpoint' => $this->endpoint,
            'provider' => $provider,
            'signatureVersion' => OssClient::OSS_SIGNATURE_VERSION_V4
        );
        $this->ossClient = new OssClient($config);
    }
    /**
     * 修改图片访问权限
     * @param $object string
     * @param $acl string default | public-read
     * @return boolean
     */
    public function setAlc($object, $acl = 'default')
    {
        $this->ossClient->putObjectAcl($this->bucket, $object, $acl);
        //  $acl = $client->getObjectAcl($bucket, $object);
        return true;
    }
    /**
     * 获取图片访问权限
     * @param $object string
     * @param $acl string default | public-read
     * @return string
     */
    public function getAlc($object)
    {
        $client = $this->ossClient;
        $bucket = $this->bucket;
        $acl = $client->getObjectAcl($bucket, $object);
        return $acl;
    }
    /**
     * 上传文件
     * @param $file
     * @param $alt string
     * @return array
     * @throws OssException
     */
    public function upload($file, $alt = '') {
        if($file->extension()) {
            $ext = $file->extension();
        } else {
            $ext = 'png';
        }
        $object = 'uploads/' . date('Ymd') . '/' . uniqid() . '.' . $ext;
        $timeout = 3600;
        $options = array(
            'Content-Type' => $this->getContentType($ext),
            OssClient::OSS_HEADERS => array(
                'Content-Disposition' => 'inline',
                'x-oss-meta-file-name' => $file->getOriginalName(),
            )
        );

        try {
            $signedUrl = $this->ossClient->signUrl($this->bucket, $object, $timeout, "PUT", $options);
            $request = new RequestCore($signedUrl);
            $request->set_method('PUT');
            $httpCore = new RequestCore($signedUrl);
            $httpCore->set_method('PUT');
            $request->add_header('Content-Type', $this->getContentType($ext));
            $request->add_header('Content-Disposition', 'inline');
            $request->add_header('x-oss-meta-file-name', $file->getOriginalName());
            $request->set_read_file($file);
            $request->set_read_stream_size(sprintf('%u', filesize($file)));
            $request->send_request();
            $res = new ResponseCore($request->get_response_header(), $request->get_response_body(), $request->get_response_code());
            if($res->isOK()) {
                if($alt) {
                    $this->setAlc($object, $alt);
                }
                return [
                    'signedUrl' => $signedUrl,
                    'path' => $object
                ];
            } else {
                throw new \Error('上传失败');
            }
        } catch (OssException $e) {
            throw new \Error($e->getMessage());
        }
    }
    /**
     * 删除文件
     * @param $path
     * @throws OssException
     */
    public function del($path) {
        $ossClient = new OssClient($this->accessKeyId, $this->accessKeySecret, $this->endpoint);
        $ossClient->deleteObject($this->bucket, $path);
    }

    /**
     * 根据path对文件进行签名
     * @param $path
     * @return string
     */
    public function signPath($path) {
        return $this->getCommonPath($path);
    }

    /**
     * 根据id对文件进行签名
     * @param $id int | string 文件id
     * @return string
     */
    public function signId($id) {
        if(empty($id)) {
            return 'https://tupian.qqw21.com/article/UploadPic/2021-7/202172122333044442.jpg';
        }
        $sql = new FileOssModal();
        $info = $sql->where('id', $id)->findOrEmpty();
        if($info->isEmpty()) {
            Log::write('文件不存在'.$id);
            throw new \Error('文件不存在');
        }
        return $this->getCommonPath($info->delPath);
    }

    /**
     * 对数组中的某个字段进行签名进行签名
     * @param $arr
     * @param $field string 字段名
     * @param $newField string 新字段名
     * @return array
     */
    public function signIds($arr, $field, $newField) {
        if(count($arr) == 0) {
            foreach($arr as $item) {
                $item[$newField] = '';
            }
            return $arr;
        }
        $ids = [];
        foreach ($arr as $item) {
            if(!empty($item[$field]) && !in_array($item[$field], $ids)) {
                $ids[] = $item[$field];
            }
        }
        $sql = new FileOssModal();
        $fileArr = $sql->whereIn('id', $ids)->select()->toArray();
        foreach ($arr as $key => $item) {
            if(!empty($item[$field])) {
                $delPath = $this->getValueById($fileArr, $item[$field]);
                $arr[$key][$newField] = $this->getCommonPath($delPath);
            }
        }
        return $arr;
    }

    /**
     * 列举文件
     * @param $prefix string 文件夹路径
     * @return array
     */
    public function getFileList($prefix)
    {
        $options = array(
            'prefix' => $prefix,
            'delimiter' => '',
        );
        $listObjectInfo = $this->ossClient->listObjectsV2($this->bucket, $options);
        $objectList = $listObjectInfo->getObjectList();
        $arr = [];
        if (!empty($objectList)) {
            foreach ($objectList as $objectInfo) {
                $arr[] = [
                    'name' => $objectInfo->getKey(),
                    'size' => $objectInfo->getSize() / 1024 / 1024
                ];
            }
        }
        return $arr;
    }

    /**
     * 根据id获取path
     * @param $arr
     * @param $id
     * @return null | string
     */

    protected function getValueById($arr, $id) {
        foreach ($arr as $item) {
            if ($item['id'] == $id) {
                return $item['delPath'];
            }
        }
        return null;
    }

    protected function getCommonPath($path, $watermark = true)
    {
        $appName = '小白圈';
        $style = "image/watermark,size_30,color_FFFFFF,text_".base64_encode($appName);
        $cacheKey = 'aliyunoss-'.$path;
        $cachePath = cache($cacheKey);
        if ($cachePath) {
            return $cachePath;
        }
        $fileExtension = pathinfo($path, PATHINFO_EXTENSION);
        if($watermark) {
            $supportArr = ['jpg', 'png', 'bmp', 'webp', 'tiff'];
            if (!in_array($fileExtension, $supportArr)) {
                $watermark = false;
            }
        }
        try {
            if($this->getAlc($path) == 'public-read') {
                $url = "https://".$this->bucket.".".$this->endpoint."/".$path;
                if($watermark) {
                    $url = $url."?x-oss-process=".$style;
                }
                return $url;
            } else {
                $timeout = 120;
                $contentType = $this->getContentType($fileExtension);
                $options= array(
                    "response-content-type"=>$contentType,
                );
                if($watermark) {
                    $options[OssClient::OSS_PROCESS] = $style;
                }
                $signedUrl = $this->ossClient->signUrl($this->bucket, $path, $timeout, "GET", $options);
                cache($cacheKey, $signedUrl, 110);
                return $signedUrl;
            }
        }  catch (OssException $e) {
            return '';
        }
    }

    protected function getContentType($extension)
    {
        $mimeTypes = [
            'jpeg' => 'image/jpeg',
            'jpg' => 'image/jpeg',
            'png' => 'image/png',
            'gif' => 'image/gif'
        ];

        return $mimeTypes[$extension] ?? 'application/octet-stream';
    }
}